﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using 项目模板2.Communication;
using Peak.Can.Basic;
using System.Net.Sockets;
using System.Net;
using System.Configuration;
using System.Threading;
using WindowsFormsApp1.Util;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Rebar;
using System.Text.RegularExpressions;
using System.Diagnostics;

namespace WindowsFormsApp1
{
    public enum CAR_TYPE
    {
        CarType_None = 0,
        CarType_EV,
        CarType_Fuel
    }
    public partial class Form1 : Form
    {

        public DeviceM ComDevice { get; set; }
        public double CurSpd { get; set; }
        public IPAddress IPAddress { get; set; }
        public int Port { get; set; }

        public IPEndPoint Ip;
        public IPEndPoint Ip2;

        public Socket client;

        uint frame_time2_delay = 0;
        uint frame_time3_delay = 0;
        uint VINMessageCount = 0;
        uint MessageCount = 0;
        bool getVIN = false;

        byte[] VinCode = new byte[17];
        string VinCodeStr = null;
        byte getVinFlg = 0;

        string str;
        CAR_TYPE CarType;

        public Thread revTh;

        System.Threading.Timer timer0;

        public bool startMonitorSpd = false;
        string message = null;
        byte revState = 0x00;

        public Form1()
        {
            InitializeComponent();

            ComDevice = new DeviceM();
            ComDevice.RecvEvent += ComDevice_RecvEvent;
            IPAddress = IPAddress.Parse(ConfigurationManager.AppSettings["remote_address"].ToString());
            Port = int.Parse(ConfigurationManager.AppSettings["remote_port"].ToString());
            Ip = new IPEndPoint(IPAddress, Port);
            CheckForIllegalCrossThreadCalls = false;
            CarType = CAR_TYPE.CarType_None;
            //timer0 = new System.Threading.Timer(FluidicFrame, null, 0, 50);

        }

        /// <summary>
        /// 车速与VIN码报文处理函数
        /// </summary>
        /// <param name="CANMsg"></param>
        private void ComDevice_RecvEvent(TPCANMsg CANMsg)
        {
            if (CANMsg.ID == 0x0CFE6CEE)//燃油车速
            {
                byte[] frame;
                byte[] temp = new byte[2];
                temp[0] = (byte)CANMsg.DATA[6];
                temp[1] = (byte)CANMsg.DATA[7];
                CurSpd = BitConverter.ToUInt16(temp, 0) * 0.00390625;
                frame = Encoding.UTF8.GetBytes(CurSpd.ToString("0.0") + "km/h");
                label2.Invoke(new Action(() => label2.Text = CurSpd.ToString("0.0") + "km/h"));
                label3.Invoke(new Action(() => label3.Text = "燃油"));

                BitConverter.ToString(temp, 0);
                if (startMonitorSpd)
                {
                    client.SendTo(frame, frame.Length, SocketFlags.None, Ip);
                }
                LogHelper.Instance.WriteLog(string.Format("Pcan get message: Id={0:X8}, Frame={1},S" +
                    "pd = {2:N2}", CANMsg.ID, BitConverter.ToString(CANMsg.DATA), CurSpd), LogType.Data);
                CarType = CAR_TYPE.CarType_Fuel;
                frame_time2_delay = 0;
                toolStripStatusLabel2.Text = ComDevice.Baud.ToString();
                revState &= 0xFE;

                byte[] txframe;
                txframe = new byte[8] { 0x03, 0x22, 0xF8, 0x02, 0x00, 0x00, 0x00, 0x00 };
                ComDevice.Write(txframe, 4, 0x18DA00F1);

            }
            else if (CANMsg.ID == 0x18FEF1D0)//纯电车速报文
            {
                byte[] frame;
                byte[] temp = new byte[2];
                temp[0] = (byte)CANMsg.DATA[1];
                temp[1] = (byte)CANMsg.DATA[2];
                CurSpd = (double)BitConverter.ToUInt16(temp, 0) / 256.0;
                frame = Encoding.UTF8.GetBytes(CurSpd.ToString("0.0") + "km/h");
                label2.Invoke(new Action(() => label2.Text = CurSpd.ToString("0.0") + "km/h"));
                label3.Invoke(new Action(() => label3.Text = "纯电"));
                if (startMonitorSpd)
                {
                    client.SendTo(frame, frame.Length, SocketFlags.None, Ip);
                }
                LogHelper.Instance.WriteLog(string.Format("Pcan get message: Id={0:X8},Frame={1},Spd = {2:N2}", CANMsg.ID, BitConverter.ToString(CANMsg.DATA), CurSpd), LogType.Data);
                CarType = CAR_TYPE.CarType_EV;
                frame_time2_delay = 0;
                toolStripStatusLabel2.Text = ComDevice.Baud.ToString();
                revState &= 0xFD;
                if (ComDevice.Baud == TPCANBaudrate.PCAN_BAUD_250K)
                {
                    revState &= 0xFE;
                }
            }
            else if (CANMsg.ID == 0x18FF55D0)//纯电VIN码
            {
                if (CANMsg.DATA[0] == 0x01)
                {
                    Array.Copy(CANMsg.DATA, 1, VinCode, 0, 7);
                    getVinFlg |= 0x01;
                }
                else if (CANMsg.DATA[0] == 0x02)
                {
                    Array.Copy(CANMsg.DATA, 1, VinCode, 7, 7);
                    getVinFlg |= 0x02;
                }
                else if (CANMsg.DATA[0] == 0x03)
                {
                    Array.Copy(CANMsg.DATA, 1, VinCode, 14, 3);
                    getVinFlg |= 0x04;
                }
                if (getVinFlg == 0x07)//接收一帧完整的VIN码
                {
                    VinCodeStr = Encoding.ASCII.GetString(VinCode, 0, 17);
                    getVinFlg = 0;
                    Regex reg = new Regex(@"^[A-Z0-9]{17}$");
                    bool result = reg.IsMatch(VinCodeStr);
                    if (result == true)
                    {
                        label5.Invoke(new Action(() => { label5.Text = VinCodeStr; }));
                        byte[] titleData = Encoding.ASCII.GetBytes("VIN=");
                        byte[] frame = new byte[21];
                        Array.Copy(titleData, 0, frame, 0, 4);
                        Array.Copy(VinCode, 0, frame, 4, 17);
                        client.SendTo(frame, frame.Length, SocketFlags.None, Ip);
                        LogHelper.Instance.WriteLog(string.Format("VIN ={0}", VinCodeStr), LogType.Data);
                        frame_time3_delay = 0;
                        getVIN = true;
                        startMonitorSpd = true;    
                    }
                }
                VINMessageCount = 0;
            }
            else if (CANMsg.ID == 0x18DAF100)//重卡
            {
                if (CANMsg.DATA[0] == 0x10)
                {
                    Array.Copy(CANMsg.DATA, 5, VinCode, 0, 3);
                    getVinFlg |= 0x01;

                    byte[] txframe;
                    txframe = new byte[8] { 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
                    ComDevice.Write(txframe, 8, 0x18DA00F1);
                }
                else if (CANMsg.DATA[0] == 0x21)
                {
                    Array.Copy(CANMsg.DATA, 1, VinCode, 3, 7);
                    getVinFlg |= 0x02;
                }
                else if (CANMsg.DATA[0] == 0x22)
                {
                    Array.Copy(CANMsg.DATA, 1, VinCode, 10, 7);
                    getVinFlg |= 0x04;
                }
                if (getVinFlg == 0x07)//接收一帧完整的VIN码
                {
                    VinCodeStr = Encoding.ASCII.GetString(VinCode, 0, 17);
                    getVinFlg = 0;
                    Regex reg = new Regex(@"^[A-Z0-9]{17}$");
                    bool result = reg.IsMatch(VinCodeStr);
                    if (result == true)
                    {
                        label5.Invoke(new Action(() => { label5.Text = VinCodeStr; }));
                        byte[] titleData = Encoding.ASCII.GetBytes("VIN=");
                        byte[] frame = new byte[21];
                        Array.Copy(titleData, 0, frame, 0, 4);
                        Array.Copy(VinCode, 0, frame, 4, 17);
                        client.SendTo(frame, frame.Length, SocketFlags.None, Ip);
                        LogHelper.Instance.WriteLog(string.Format("VIN ={0}", VinCodeStr), LogType.Data);
                        frame_time3_delay = 0;
                        getVIN = true;
                        startMonitorSpd = true;
                    }
                }
                CarType = CAR_TYPE.CarType_Fuel;
                VINMessageCount = 0;
            }
            else if (CANMsg.ID == 0x18EBFFD0)//轻卡
            {
                if (CANMsg.DATA[0] == 0x01)
                {
                    Array.Copy(CANMsg.DATA, 1, VinCode, 0, 7);
                    getVinFlg |= 0x01;

                    byte[] txframe;
                    txframe = new byte[8] { 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
                    ComDevice.Write(txframe, 8, 0x18DA00F1);
                }
                else if (CANMsg.DATA[0] == 0x02)
                {
                    Array.Copy(CANMsg.DATA, 1, VinCode, 7, 7);
                    getVinFlg |= 0x02;
                }
                else if (CANMsg.DATA[0] == 0x03)
                {
                    Array.Copy(CANMsg.DATA, 1, VinCode, 14, 3);
                    getVinFlg |= 0x04;
                }
                if (getVinFlg == 0x07)//接收一帧完整的VIN码
                {
                    VinCodeStr = Encoding.ASCII.GetString(VinCode, 0, 17);
                    getVinFlg = 0;
                    Regex reg = new Regex(@"^[A-Z0-9]{17}$");
                    bool result = reg.IsMatch(VinCodeStr);
                    if (result)
                    {
                        label5.Invoke(new Action(() => { label5.Text = VinCodeStr; }));
                        byte[] titleData = Encoding.ASCII.GetBytes("VIN=");
                        byte[] frame = new byte[21];
                        Array.Copy(titleData, 0, frame, 0, 4);
                        Array.Copy(VinCode, 0, frame, 4, 17);
                        client.SendTo(frame, frame.Length, SocketFlags.None, Ip);
                        LogHelper.Instance.WriteLog(string.Format("VIN ={0}", VinCodeStr), LogType.Data);
                        frame_time3_delay = 0;
                        getVIN = true;
                        startMonitorSpd = true;
                    }
                }
                CarType = CAR_TYPE.CarType_Fuel;
                VINMessageCount = 0;
            }
            MessageCount = 0;
        }

        /// <summary>
        /// 设备初始化
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Load(object sender, EventArgs e)
        {
            //byte[] data;
            string err_message;
            bool res = ComDevice.InitDevice(TPCANBaudrate.PCAN_BAUD_250K, PCANBasic.PCAN_USBBUS1, DeviceProtocol.DEVICE_MODE_BASIC, out err_message);
            if (!res)
            {
                LogHelper.Instance.WriteLog("Pcan Init failed:" + err_message, LogType.Failure);
                if (MessageBox.Show("设备打开失败：" + err_message, "故障提示", MessageBoxButtons.OK) == DialogResult.OK)
                {
                    this.Close();
                    return;
                }
            }
            else
            {
                ComDevice.Open();
            }

#if true
            client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
#endif
            timer2.Enabled = true;
            timer3.Enabled = true;

        }

        /// <summary>
        /// 初始化函数
        /// </summary>
        /// <param name="baud"></param>
        /// <returns></returns>
        public bool InitDevice(TPCANBaudrate baud)
        {
            string err_message;
            bool res = ComDevice.InitDevice(baud, PCANBasic.PCAN_USBBUS1, DeviceProtocol.DEVICE_MODE_BASIC, out err_message);
            if (!res)
            {
                LogHelper.Instance.WriteLog("Pcan Init failed:" + err_message, LogType.Failure);
            }
            else
            {
                ComDevice.Open();
            }
            return res;
        }

        /// <summary>
        /// 设备关闭
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (ComDevice.InitState)
            {
                timer2.Stop();
                timer3.Stop();
                ComDevice.Close();
                client.Close();
            }
        }

        /// <summary>
        /// 设备状态判断与波特率检测以及VIN码请求报文定是函数（1s）
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer2_Tick(object sender, EventArgs e)
        {
            byte[] txframe;
            if ((frame_time2_delay >= 5))
            {
                if (ComDevice.Baud == TPCANBaudrate.PCAN_BAUD_250K)
                {
                    revState |= 0x01;
                    ComDevice.Reset();
                    InitDevice(TPCANBaudrate.PCAN_BAUD_500K);

                }
                else
                {
                    revState |= 0x02;
                    ComDevice.Reset();
                    InitDevice(TPCANBaudrate.PCAN_BAUD_250K);

                }
                frame_time2_delay = 0;
                message = null;
            }
            if (revState == 0x03)
            {
                toolStripStatusLabel4.Text = "离线";
                toolStripStatusLabel2.Text = "0Kps";
                label2.Text = "0 km/h";
                startMonitorSpd = false;
                getVIN = false;
                ComDevice.getMessages = false;
                revState = 0x00;
                CarType = CAR_TYPE.CarType_None;
            }
            else if (revState != 0x03 && ComDevice.getMessages == true)
            {
                toolStripStatusLabel4.Text = "在线";
            }
            frame_time2_delay++;

            #region 燃油车获取VIN码
            if (CarType == CAR_TYPE.CarType_Fuel)
            {
                if (ComDevice.Baud == TPCANBaudrate.PCAN_BAUD_250K)
                {
                    //txframe = new byte[8] { 0x03, 0x22, 0xF8, 0x02, 0x00, 0x00, 0x00, 0x00 };
                    //ComDevice.Write(txframe, 4, 0x18DA00F1);
                }
                else if (ComDevice.Baud == TPCANBaudrate.PCAN_BAUD_500K)
                {
                    txframe = new byte[8] { 0xEC, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
                    ComDevice.Write(txframe, 3, 0x18EAFF21);
                }
            }
            #endregion
        }

        /// <summary>
        /// VIN码状态检测函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer3_Tick(object sender, EventArgs e)
        {
            if (VINMessageCount >= 10 && getVIN == false)
            {
                label5.Invoke(new Action(() => { label5.Text = "未检测到VIN!"; }));
                client.SendTo(Encoding.UTF8.GetBytes("01"), Ip);
                startMonitorSpd = true;
            }
            if (frame_time3_delay >= 6 && getVIN == false && VINMessageCount < 5)
            {
                label5.Invoke(new Action(() => { label5.Text = "VIN码格式不正确"; }));
                client.SendTo(Encoding.UTF8.GetBytes("01"), Ip);
                startMonitorSpd = true;
                frame_time3_delay = 0;
            }
            frame_time3_delay++;
            VINMessageCount++;
        }

        /// <summary>
        /// 流控帧发送定时函数（50ms）
        /// </summary>
        /// <param name="obj"></param>
        public void FluidicFrame(object obj)
        {
            byte[] txframe;
            txframe = new byte[8] { 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
            if (CarType != CAR_TYPE.CarType_None)
            {
                ComDevice.Write(txframe, 8, 0x18DA00F1);
            }

        }
    }
}
